package dd.prog2.musterExercises.ws12set13_4_mvc.game;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * Implements an iterative deepening Minimax search with alpha-beta pruning and
 * a special action ordering optimized for the Connect Four game.
 * 
 * @author Ruediger Lunde
 */
public class ConnectFourPlayer extends
		IterativeDeepeningAlphaBetaSearch<ConnectFourState, Integer, String> {
	// private HashMap<ConnectFourState, Double> valueHash = new
	// HashMap<ConnectFourState, Double>();

	public ConnectFourPlayer(ConnectFourGame game, int time) {
		super(game, 0.0, 1.0, time);
	}

	protected void incrementDepthLimit() {
		// System.out.println(expandedNodes + " " + valueHash.size());
		// expandedNodes = 0; valueHash.clear();
		super.incrementDepthLimit();
	}

	@Override
	protected boolean isSignificantlyBetter(double newUtility, double utility) {
		return newUtility - utility > (utilMax - utilMin) * 0.4;
	}

	@Override
	protected boolean hasSafeWinner(double resultUtility) {
		return Math.abs(resultUtility - (utilMin + utilMax) / 2) > 0.4
				* utilMax - utilMin;
	}

	/**
	 * Modifies the super implementation by making safe winner values even more
	 * attractive if depth is small.
	 */
	@Override
	protected double eval(ConnectFourState state, String player, int depth) {
		// Double v = null; //valueHash.get(state);
		double value;
		// if (v == null) {
		value = super.eval(state, player, depth);
		if (hasSafeWinner(value)) {
			if (value > (utilMin + utilMax) / 2)
				value -= state.getMoves() / 1000.0;
			else
				value += state.getMoves() / 1000.0;
		} else {
			if (player == game.getPlayers()[0])
				value += (state.winPositions1 - state.winPositions2) / 100.0;
			else
				value -= (state.winPositions1 - state.winPositions2) / 100.0;
		}

		// v =(player == game.getPlayers()[1]) ? 1 - value : value;
		// valueHash.put(state, v);
		// } else {
		// value = (player == game.getPlayers()[1]) ? 1 - v : v;
		// }
		return value;
	}

	/**
	 * Orders actions with respect to the number of potential win positions
	 * which profit from the action.
	 */
	@Override
	public List<Integer> orderActions(ConnectFourState state,
			List<Integer> actions, String player, int depth) {
		List<Integer> result = new ArrayList<Integer>();
		int playerNum = ((ConnectFourGame) game).getPlayerNum(player);
		if (depth == 0) {
			List<ActionValuePair<Integer>> actionEstimates = new ArrayList<ActionValuePair<Integer>>(
					actions.size());
			for (Integer action : actions) {
				int value = Integer.MAX_VALUE;
				if (!state.isWinMoveFor(action, playerNum))
					value = state.analyzePotentialWinPositions(action);
				actionEstimates.add(ActionValuePair.createFor(action, value));
			}
			Collections.sort(actionEstimates);
			for (ActionValuePair<Integer> pair : actionEstimates)
				result.add(pair.getAction());
		} else { // fast version putting win moves in front
			for (Integer action : actions) {
				if (state.isWinMoveFor(action, playerNum))
					result.add(0, action);
				else
					result.add(action);
			}
		}
		return result;
	}
	
	/**
	 * Helper class for action ordering.
	 * @author Ruediger Lunde
	 */
	public static class ActionValuePair<ACTION> implements Comparable<ActionValuePair<ACTION>> {
		private ACTION action;
		private double value;
		
		public static <ACTION> ActionValuePair<ACTION> createFor(ACTION action, double utility) {
			return new ActionValuePair<ACTION>(action, utility);
		}
		
		public ActionValuePair(ACTION action, double utility) {
			this.action = action;
			this.value = utility;
		}
		
		public ACTION getAction() {
			return action;
		}

		public double getValue() {
			return value;
		}

		@Override
		public int compareTo(ActionValuePair<ACTION> pair) {
			if (value < pair.value)
				return 1;
			else if (value > pair.value)
				return -1;
			else
				return 0;
		}
	}
}
